package com.motu.monstercity.server.game.logichandler;

import com.motu.monstercity.module.common.iap.IapGiftPush;
import com.motu.monstercity.module.common.network.RequestParam;
import com.motu.monstercity.protocol.Common.PBUserCityCoord;
import com.motu.monstercity.protocol.Common.PBUserData;
import com.motu.monstercity.protocol.CsGameBuild.*;
import com.motu.monstercity.server.game.base.AllParam;
import com.motu.monstercity.server.game.base.CommonUtils;
import com.motu.monstercity.server.game.base.ProtoDataUtils;
import com.motu.monstercity.server.game.commondata.bag.ItemId;
import com.motu.monstercity.server.game.commondata.build.*;
import com.motu.monstercity.server.game.commondata.maintask.MainTaskConstant;
import com.motu.monstercity.server.game.commondata.partner.PartnerConstant;
import com.motu.monstercity.server.game.commondata.skill.SkillConstant;
import com.motu.monstercity.server.game.commondata.system.SystemConstant;
import com.motu.monstercity.server.game.commondata.system.UserExp;
import com.motu.monstercity.server.game.commondata.world.WorldRadar;
import com.motu.monstercity.server.game.log.LogType;
import com.motu.monstercity.server.game.logic.*;
import com.motu.monstercity.server.game.userdata.*;
import com.motu.monstercity.server.game.verticle.MainVerticle;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.toolset.ErrorWord;
import com.motu.vertx.module.utility.toolset.SensitivewordEngine;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.json.JsonArray;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class BuildHandler {
    // CMD_GAME_BUILD_MAIN_INFO = 70700; // 建筑模块主界面 [2]每次打开请求,商业建筑的赚速会更新
    public static Object CMD_GAME_BUILD_MAIN_INFO(RequestParam clientParam) throws Exception {
        CSGameBuildMainInfoRequest request = CSGameBuildMainInfoRequest.parseFrom(clientParam.getData());
        CSGameBuildMainInfoResponse.Builder response = CSGameBuildMainInfoResponse.newBuilder();
        long userId = clientParam.getUserId();

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        List<UserBuild> userBuildList = BuildManager.getUserBuildList(userId);
        for (UserBuild userBuild : userBuildList) {
            ProtoDataUtils.updatePBUserData(pbUserData, userBuild, true);
        }

        return response;
    }

    // CMD_GAME_BUILD_UNLOCK = 70701; // 解锁
    public static Object CMD_GAME_BUILD_UNLOCK(RequestParam clientParam) throws Exception {
        CSGameBuildUnlockRequest request = CSGameBuildUnlockRequest.parseFrom(clientParam.getData());
        CSGameBuildUnlockResponse.Builder response = CSGameBuildUnlockResponse.newBuilder();
        long userId = clientParam.getUserId();

        int buildId = request.getBuildId();
        BuildMain buildMain = BuildManager.getBuildMain(buildId);
        if (buildMain == null || buildMain.getUnlockType() == 1) {
            return ErrorWord.NOT_DATA;// 只能从可修复的建筑废墟解锁
        }

        UserInfo userInfo = GameUser.getUserInfo(userId);
        if (!BuildManager.isCanUnlock(buildMain, userInfo)) {
            return ErrorWord.WRONG_STATUS;//未达到解锁条件
        }

        UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
        if (userBuild != null && userBuild.isUnlock()) {
            return ErrorWord.REPEATED_OPERATION;// 已经解锁过了
        }

        List<RewardItem> costItem = null;// 需要消耗的道具
        if (!Tool.isEmpty(buildMain.getUnlockPlaceItem())) {
            costItem = CommonUtils.takeReawrdItemFromStr(buildMain.getUnlockPlaceItem());
            if (costItem.size() > 0 && !BagManager.checkNeedItemNum(userInfo, costItem)) {
                return ErrorWord.ITEM_LACK;// 道具不足
            }
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserPower userPower = GameUser.getUserPower(userId);
        if (costItem != null && costItem.size() > 0) {
            RewardManager.subReward(userInfo, costItem, pbUserData, LogType.BUILD_UNLOCK, buildId);
        }
        if (userBuild != null) {
            userBuild.putIsUnlock(1);
            userBuild.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userBuild);
        } else {
            userBuild = new UserBuild(userId, buildId, 1, 1);// 创建用户数据
            userBuild.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userBuild, true);
        }
        if (buildMain.isDecorateBuild())  {// 对商业建筑有加成，需要更新商业建筑的加成值
            BuildManager.handleBuildUnlock(pbUserData, userInfo, userPower, buildMain);
        }

        return response;
    }

    // CMD_GAME_BUILD_LEVEL_UP = 70702; // 升级
    public static Object CMD_GAME_BUILD_LEVEL_UP(RequestParam clientParam) throws Exception {
        CSGameBuildLevelUpRequest request = CSGameBuildLevelUpRequest.parseFrom(clientParam.getData());
        CSGameBuildLevelUpResponse.Builder response = CSGameBuildLevelUpResponse.newBuilder();
        long userId = clientParam.getUserId();

        int buildId = request.getBuildId();
        BuildMain buildMain = BuildManager.getBuildMain(buildId);
        if (buildMain == null) {
            return ErrorWord.NOT_DATA;
        }
        UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
        if (userBuild == null) {
            return ErrorWord.BAD_PARAM;//
        }

        if (!userBuild.isPlace()) {
            return ErrorWord.WRONG_STATUS;// 建筑未摆放不能升级
        }

        UserInfo userInfo = GameUser.getUserInfo(userId);
        List<RewardItem> needItem = new ArrayList<>();// 升级需要的消耗
        int curLevel = userBuild.getLevel();
        int nexLevel = curLevel + 1;

        // 市政类建筑的升级走独立的配置表,后续有的在这边加
        if (buildMain.isCityCenter())  {// 市政中心升级单独的逻辑
            UserExp userExp = GameDataManager.getUserExp(curLevel);
            UserExp userExpNext = GameDataManager.getUserExp(nexLevel);
            if (userExp == null || userExpNext == null) {
                return ErrorWord.NOT_DATA;
            }
            if (!BuildManager.isCityCenterLevelUp(userInfo, userExpNext)) {
                return ErrorWord.WRONG_STATUS;//市政中心还不能升级
            }
        } else if (buildMain.isBuildBank()) {// 金库的升级
            BuildBank buildBank = BuildManager.getBuildBank(curLevel);
            BuildBank buildBankNext = BuildManager.getBuildBank(nexLevel);
            if (buildBank == null || buildBankNext == null) {
                return ErrorWord.NOT_DATA;
            }
            needItem = CommonUtils.takeReawrdItemFromStr(buildBank.getUpgradeConsume());// 升级需要的消耗
        } else if (buildMain.isBuildRadar()) {// 雷达走表world_radar 的配置
            WorldRadar worldRadar = WorldManager.getWorldRadar(curLevel);
            WorldRadar worldRadarNext = WorldManager.getWorldRadar(nexLevel);
            if (worldRadar == null || worldRadarNext == null) {
                return ErrorWord.NOT_DATA;
            }
            needItem = CommonUtils.takeReawrdItemFromStr(worldRadar.getUpgradeConsume());// 升级需要的消耗
        }
        else {// 非市政类建筑升级统一走build_upgrade 配置表
            BuildUpgrade curConfig = BuildManager.getBuildUpgrade(buildId, curLevel);
            BuildUpgrade nextConfig = BuildManager.getBuildUpgrade(buildId, nexLevel);
            if (curConfig == null || nextConfig == null) {
                return ErrorWord.NOT_DATA;
            }
            needItem = CommonUtils.takeReawrdItemFromStr(curConfig.getConsume());// 需要消耗的道具
        }

        if (needItem.size() > 0 && !BagManager.checkNeedItemNum(userInfo, needItem)) {
            return ErrorWord.ITEM_LACK;
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserPower userPower = GameUser.getUserPower(userId);
        RewardManager.subReward(userInfo, needItem, pbUserData, LogType.BUILD_LEVEL_UP, buildId + "_" + curLevel);
        userBuild.putLevel(nexLevel);
        if (buildMain.isCityCenter()) {
            MainTaskManager.resendCityTaskReward(pbUserData, userInfo, nexLevel);// 城市升级时补发，补发未领取的城市任务奖励
            MainTaskManager.autoGetCityLevelReward(pbUserData, userInfo, nexLevel);// 城市中心升级时，自动领取都市等级福利的奖励

            userInfo.putLevel(nexLevel);
            UserAffair userAffair = GameUser.getUserAffair(userId);
            UserStage userStage = FightManager.getUserStage(userId);
            SystemManager.checkSystemModelOpen(pbUserData, userInfo, userAffair, userStage, SystemConstant.SYSTEM_MODULE_ID_PATROL);
            userInfo.update(pbUserData);// 更新userinfo并下发给客户端

            UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
            userCityInfo.putDailyDiamondTime(0);
            userCityInfo.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);// 升级后可以领取每日礼包

            UserExp userExpNext = GameDataManager.getUserExp(nexLevel);
            if (!Tool.isEmpty(userExpNext.getReward())) {
                RewardManager.addReward(userInfo, CommonUtils.takeReawrdItemFromStr(userExpNext.getReward()), pbUserData, LogType.BUILD_LEVEL_UP);
            }

            //TODO 升级触发一些信息刷新，看后面需不需要挪走统一处理
            DatingManager.levelUpToUpdateUserDating(curLevel, nexLevel, userId);
            ChildManager.unlockClassRoom(pbUserData, userInfo);
            GameIapManager.checkTriggerIapGiftPush(userInfo, IapGiftPush.TYPE_LEVEL, nexLevel); // 检查等级礼包
            MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_113, userBuild.getLevel());// 更新主线任务,成就,日常任务的进度
            RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_113, userBuild.getLevel());
        }

        // 商业建筑 会影响本身的城市收益
        if (buildMain.isBusinessBuild()) {
            long addValue = userBuild.reCountEarn(userInfo, userPower);
            if (addValue > 0) {
                userPower.addBuildEarn(pbUserData, userInfo, addValue);
            }
        }

        userBuild.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userBuild);

        // 银行的升级会影响各个商业建筑的城市收益
        if (buildMain.isBuildBank()) {
            BuildManager.handleBankLevelUp(pbUserData, userInfo, userPower, userBuild);
            MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_102, userBuild.getLevel());// 更新主线任务,成就,日常任务的进度
            RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_102, userBuild.getLevel());
        }

        // 雷达升级会影响战力，影响各个商业建筑的城市收益
        if (buildMain.isBuildRadar()) {
            userPower.updatePowerAddWorldCv(pbUserData, userInfo, userBuild);
            UserWorldEventLocation userWorldEventLocation = WorldManager.unlockOfferEvent(userInfo);
            if (userWorldEventLocation != null) {// 有解锁悬赏事件
                ProtoDataUtils.updatePBUserData(pbUserData, userWorldEventLocation, true);
            }

            //雷达升级刷新事件
            UserWorldInfo userWorldInfo = WorldManager.getUserWorldInfo(userId);
            WorldRadar worldRadar = WorldManager.getWorldRadar(nexLevel);
            WorldManager.refreshWorldTeam(pbUserData, userInfo, userWorldInfo);// 刷新结算行军队列，未到达则不做更新，已达到，则更新队伍，清除事件坑位里的数据，如果已返回基地，则生成战报，更新干员信息，伤兵信息
            WorldManager.refreshEvent(userId, userWorldInfo, worldRadar);// 刷新事件，放到事件队列里面
            List<UserWorldEventLocation> locationList = WorldManager.getUserWorldEventLocationList(userInfo.getId());
            WorldManager.updateAllEventLocation(userInfo, userWorldInfo, worldRadar, locationList, true);// 从事件队列里取事件更新到事件坑位
            for (UserWorldEventLocation entity : locationList) {
                if (entity.isCommonType()) {
                    ProtoDataUtils.updatePBUserData(pbUserData, entity);
                }
            }

            MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_255, userBuild.getLevel());// 雷达等级提升至{0}级
        }

        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_105, 1, buildId);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_105, 1, buildId);
        int totalLevel = BuildManager.countBusinessBuildLevel(userId);// 商业建筑的总等级
        MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_43, totalLevel);// 领取完奖励会重置进度 更新主线任务,成就,日常任务的进度
        MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_129, totalLevel);// 更新主线任务,成就,日常任务的进度
        RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_43, totalLevel);
        RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_129, totalLevel);
        BuildManager.updateMainTaskNum(pbUserData, userInfo);// TASK_TYPE_123 = 123;// {0}间商铺达到{1}级（0：x间建筑）
        SystemManager.tryUnlockSystem(pbUserData,userInfo,SystemConstant.SYSTEM_MODULE_ID_DISCOUNT_GIFT);  //  尝试解锁  TODO 目前是同步响应里塞数据是否异步+推送的形式更好
        return response;
    }

    // CMD_GAME_BUILD_SAVE_PLACE = 70703; // 摆放， 建筑解锁就可以摆放，是否可以重复摆放由客户端限制
    public static Object CMD_GAME_BUILD_SAVE_PLACE(RequestParam clientParam) throws Exception {
        CSGameBuildSavePlaceRequest request = CSGameBuildSavePlaceRequest.parseFrom(clientParam.getData());
        CSGameBuildSavePlaceResponse.Builder response = CSGameBuildSavePlaceResponse.newBuilder();
        long userId = clientParam.getUserId();

        PBUserCityCoord coord = request.getCoord();
        long key = BuildManager.takeCoord(coord.getX(), coord.getY(), coord.getZ());
        int buildId = coord.getItemId();
        BuildMain buildMain = BuildManager.getBuildMain(buildId);
        UserInfo userInfo = GameUser.getUserInfo(userId);
        if (buildMain == null) {
            return ErrorWord.BAD_PARAM;
        }
        List<RewardItem> needItem = CommonUtils.takeReawrdItemFromStr(buildMain.getPlaceItem());// 需要消耗的道具
        if (needItem.size() > 0 && !BagManager.checkNeedItemNum(userInfo, needItem)) {
            return ErrorWord.ITEM_LACK;
        }

        UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
        if (!BuildManager.checkBuildCanPlace(buildMain, userBuild)) {
            return ErrorWord.WRONG_STATUS;// 建筑未解锁
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        if (needItem != null) {
            RewardManager.subReward(userInfo, needItem, pbUserData, LogType.BUILD_PLACE);
        }

        // 生成新的坐标信息并下发客户端
        UserCityCoord userCityCoord = BuildManager.getUserCityCoord(userId, key);
        BuildManager.creatUserCityCoord(pbUserData, userCityCoord, userId, key, buildId, coord.getIsTurn(), coord.getParam(), TimeUtils.getCurTime());

        UserPower userPower = GameUser.getUserPower(userId);
        if (buildMain.isCityBuild() || buildMain.isBusinessBuild()) {
            if (userBuild == null) {// 默认解锁的建筑要先创建userbuild数据
                userBuild = new UserBuild(userId, buildId, 1, 1);
                userBuild.putIsPlace(pbUserData, userInfo, userPower);//
                userBuild.doCreate();
                ProtoDataUtils.updatePBUserData(pbUserData, userBuild, true);
            } else {
                userBuild.putIsPlace(pbUserData, userInfo, userPower);//
                userBuild.update();
                ProtoDataUtils.updatePBUserData(pbUserData, userBuild);
            }
        }

        if (buildMain.getPeasonLimit() > 0) {// 摆放民房会增加居民楼的数量
            UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
            userCityInfo.addPeasonMax(pbUserData, userInfo, buildMain.getPeasonLimit());
            userCityInfo.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);
        }
        if (buildMain.isBusinessBuild()) {
            int totalLevel = BuildManager.countBusinessBuildLevel(userId);// 商业建筑的总等级
            MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_129, totalLevel);// 更新主线任务,成就,日常任务的进度
            RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_129, totalLevel);
        }
        if (buildMain.getBuildId() == BuildConstant.BUILD_ID_TRANSFER) {//摆放交易站
            UserSnatchInfo userSnatchInfo = FightManager.getUserSnatchInfo(userId);
            userSnatchInfo.putTransferTime(TimeUtils.getCurTime());
            userSnatchInfo.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userSnatchInfo);// 建造交易站之后才开始计算挂机金币
        }
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_103, 1, buildId);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_103, 1, buildId);

        return response;
    }

    // CMD_GAME_BUILD_SAVE_MOVE = 70707; // 建筑移动
    public static Object CMD_GAME_BUILD_SAVE_MOVE(RequestParam clientParam) throws Exception {
        CSGameBuildSaveMoveRequest request = CSGameBuildSaveMoveRequest.parseFrom(clientParam.getData());
        CSGameBuildSaveMoveResponse.Builder response = CSGameBuildSaveMoveResponse.newBuilder();
        long userId = clientParam.getUserId();

        PBUserCityCoord coord = request.getCoord();
        long key = BuildManager.takeCoord(coord.getX(), coord.getY(), coord.getZ());
        PBUserCityCoord coordNew = request.getCoordNew();
        long keyNew = BuildManager.takeCoord(coordNew.getX(), coordNew.getY(), coordNew.getZ());

        UserCityCoord userCityCoord = BuildManager.getUserCityCoord(userId, key);// 原来的建筑
        BuildInitCoord buildInitCoord = BuildManager.getBuildInitCoord(key);// 初始地图数据
        JsonArray jsonArray = new JsonArray();//
        int buildId = 0;// 建筑id
        if (userCityCoord != null) {
            buildId = userCityCoord.getItemId();
        } else if (buildInitCoord != null) {
            buildId  = buildInitCoord.getBuildId();
            jsonArray.add(buildInitCoord.getCrood());
        }

        if (buildId == 0)  {
            return ErrorWord.NOT_DATA_1;
        }

        int isTurn = userCityCoord != null ? userCityCoord.getIsTurn() : buildInitCoord.getIsTurn();// 是否翻转
        String param = userCityCoord != null ? userCityCoord.getParam() : "";// 参数
        long buildTime = userCityCoord != null ? userCityCoord.getBuildTime() : TimeUtils.getCurTime();// 建造时间

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();

        // 生成新的坐标信息,并下发给客户端
        UserCityCoord userCityCoordNew = BuildManager.getUserCityCoord(userId, keyNew);
        BuildManager.creatUserCityCoord(pbUserData, userCityCoordNew, userId, keyNew, buildId, isTurn, param, buildTime);

        // 清除坐标信息,并下发给客户端
        BuildManager.clearUserCityCoord(pbUserData, userCityCoord);// 清除坐标信息,并下发给客户端,item_id=0时客户端不显示

        // 是否有拆除初始地图的坐标信息
        if (jsonArray.size()  > 0) {
            BuildManager.noticeLoadInitCoord(userId, jsonArray);// 通知gameinit 进程,异步生成初始地图的数据
        }

        return response;
    }

    // CMD_GAME_BUILD_COORD_CLEAR = 70704; // 清除某坐标的建筑,如道路,民房
    public static Object CMD_GAME_BUILD_COORD_CLEAR(RequestParam clientParam) throws Exception {
        CSGameBuildCoordClearRequest request = CSGameBuildCoordClearRequest.parseFrom(clientParam.getData());
        CSGameBuildCoordClearResponse.Builder response = CSGameBuildCoordClearResponse.newBuilder();
        long userId = clientParam.getUserId();

        List<PBUserCityCoord> list = request.getCoordsList();
        JsonArray keyList = new JsonArray();// 坐标列表
        for (PBUserCityCoord pbUserCityCoord : list) {
            long key = BuildManager.takeCoord(pbUserCityCoord.getX(), pbUserCityCoord.getY(), pbUserCityCoord.getZ());
            keyList.add(key);
        }
        ConcurrentHashMap<Long, UserCityCoord> userCityCoordList = BuildManager.getUserCityCoordList(userId, keyList);

        for (UserCityCoord userCityCoord : userCityCoordList.values()) {
            int buildId = userCityCoord.getItemId();
            BuildMain buildMain = BuildManager.getBuildMain(buildId);
            if (buildMain == null) {
                return ErrorWord.NOT_DATA;
            }
            if (buildMain.isCityBuild() || buildMain.isBusinessBuild()) {
                return ErrorWord.BAD_PARAM;// 主建筑和商业建筑不能清除
            }
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        int subPeason = 0;// 减少的人口上限数量
        for (UserCityCoord userCityCoord : userCityCoordList.values()) {
            int buildId = userCityCoord.getItemId();
            BuildMain buildMain = BuildManager.getBuildMain(buildId);
            if (buildMain.getPeasonLimit() > 0) {// 拆除民房会减少人口上限
                subPeason += buildMain.getPeasonLimit();
            }
            BuildManager.clearUserCityCoord(pbUserData, userCityCoord);// 清除坐标信息,并下发给客户端,item_id=0时客户端不显示
        }
        if (subPeason > 0) {
            UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
            if (subPeason >= userCityInfo.getPeasonMax()) {
                subPeason = userCityInfo.getPeasonMax();
            }
            userCityInfo.addPeasonMax(pbUserData, userInfo, -subPeason);
            userCityInfo.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);
        }

        // 是否有拆除初始地图的坐标信息
        JsonArray jsonArray = BuildManager.getInitCoordList(keyList, userCityCoordList);// 获取拆除列表里面的初始地图的坐标列表
        if (jsonArray.size()  > 0) {
            BuildManager.noticeLoadInitCoord(userId, jsonArray);// 通知gameinit 进程,异步生成初始地图的数据
        }

        return response;
    }


    // CMD_GAME_BUILD_RECRUIT = 70705; // 招募 经营优化
    public static Object CMD_GAME_BUILD_RECRUIT(RequestParam clientParam) throws Exception {
        CSGameBuildRecruitRequest request = CSGameBuildRecruitRequest.parseFrom(clientParam.getData());
        CSGameBuildRecruitResponse.Builder response = CSGameBuildRecruitResponse.newBuilder();
        long userId = clientParam.getUserId();

        int buildId = request.getBuildId();
        int num = request.getNum();
        if (num < 0 || num > 999) {
            return ErrorWord.BAD_PARAM;
        }
        BuildMain buildMain = BuildManager.getBuildMain(buildId);
        if (buildMain == null || !buildMain.isBusinessBuild()) {
            return ErrorWord.NOT_DATA;// 不是商业类建筑不能招募
        }
        UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
        if (userBuild == null || !userBuild.isPlace()) {
            return ErrorWord.WRONG_STATUS;// 尚未解锁或是 未摆放
        }

        int curNum = userBuild.getRecruitNum();// 当前的招募次数
        int itemId = ItemId.GOLD;// 招募固定消耗金币
        UserInfo userInfo = GameUser.getUserInfo(userId);
        int skillAdd = SkillManager.getSkillMoudleAdd(userId, SkillConstant.EFFECT_TYPE_8, buildMain.getCharacterType());//技能减少招募花费
        long itemNum = BagManager.getUserItemNum(userInfo, itemId);// 总的有多少金币
        if (itemNum < buildMain.takeRcruitConsume(curNum, skillAdd)) {
            return ErrorWord.ITEM_LACK;// 道具最少要够经营1次
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        if (num == 0) {
            num = 1;// 最少1次
        }
        int endNum;// 点击后的经营次数
        int maxNum = BuildManager.getMaxRecruitNum();
        if (curNum + num > maxNum) {
            endNum = maxNum;
        } else {
            endNum = curNum + num;
        }

        long subTotal = 0;// 总的要扣除的道具数量
        int addNum = 0;// 实际招募的数量 实际增加的经营次数
        for (int i=curNum;i<endNum;i++) {
            long consume = buildMain.takeRcruitConsume(i, skillAdd);
            if (itemNum >= consume) {
                itemNum = itemNum - consume;
                subTotal += consume;
                addNum++;
            } else {
                break;
            }
        }

        UserPower userPower = GameUser.getUserPower(userId);
        RewardManager.subReward(userInfo, itemId, subTotal, pbUserData, LogType.BUILD_RECRUIT, buildId + "_" + userBuild.getRecruitNum());
        long addValue = userBuild.addRecruitNum(userInfo, userPower, addNum);
        userBuild.unlockPartnerSeat();// 根据招募次数解锁委派槽位
        userBuild.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userBuild);
        if (addValue > 0) {
            userPower.addBuildEarn(pbUserData, userInfo, addValue);
        }
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_2, addNum);// 更新主线任务,成就,日常任务的进度
        MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_104, userBuild.getRecruitNum(), buildId);// 更新主线任务,成就,日常任务的进度
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_130, addNum);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_2, addNum);
        RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_104, userBuild.getRecruitNum(), buildId);
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_130, addNum);

        return response;
    }

    // CMD_GAME_BUILD_PARTNER_SEND = 70706; // 派遣干员
    public static Object CMD_GAME_BUILD_PARTNER_SEND(RequestParam clientParam) throws Exception {
        CSGameBuildPartnerSendRequest request = CSGameBuildPartnerSendRequest.parseFrom(clientParam.getData());
        CSGameBuildPartnerSendResponse.Builder response = CSGameBuildPartnerSendResponse.newBuilder();
        long userId = clientParam.getUserId();

        int buildId = request.getBuildId();
        JsonArray partnerIdList = new JsonArray();
        for (int partnerId : request.getPartnerListList()) {
            partnerIdList.add(partnerId);
        }
        BuildMain buildMain = BuildManager.getBuildMain(buildId);
        if (buildMain == null || !buildMain.isBusinessBuild()) {
            return ErrorWord.NOT_DATA;// 不是商业类建筑不能委派
        }
        UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
        if (userBuild == null || !userBuild.isPlace()) {
            return ErrorWord.WRONG_STATUS;// 尚未解锁或是 未摆放
        }

        if (partnerIdList.size() > userBuild.getSeatNum()) {
            return ErrorWord.WRONG_STATUS;// 委派槽位不足
        }

        ConcurrentHashMap<Integer, UserPartner> userPartnerList = BuildManager.getUserPartnerList(userId, partnerIdList);
        if (userPartnerList.size() != partnerIdList.size()) {
            return ErrorWord.WRONG_STATUS;// 有未获得的干员
        }


        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        UserPower userPower = GameUser.getUserPower(userId);
        long addValueEarn = 0L;// 增加的城市收益
        for (int i=0; i<partnerIdList.size(); i++) {
            int partnerId = partnerIdList.getInteger(i);//
            UserPartner userPartner = userPartnerList.get(partnerId);
            int buildIdOld = userPartner.getBuildId();//
            if (buildIdOld != buildId) {// 派遣的建筑有变化
                userPartner.putBuildId(buildId);
                userPartner.update();// 更新伙伴数据里的委派建筑Id
                ProtoDataUtils.updatePBUserData(pbUserData, userPartner);
                if (buildIdOld > 0) {
                    UserBuild userBuildOld = BuildManager.getUserBuild(userId, buildIdOld);
                    addValueEarn += userBuildOld.removePartnerId(pbUserData, userInfo, userPower, partnerId);
                    userBuildOld.update();
                    ProtoDataUtils.updatePBUserData(pbUserData, userBuildOld);
                }
            }
        }
        JsonArray listOld = userBuild.getPartnerArray();// 原来的委派列表
        for (int i=0; i<listOld.size(); i++) {
            int partnerId = listOld.getInteger(i);//
            if (!Tool.isInList(partnerIdList, partnerId)) {// 更新替换下来的伙伴的委派数据
                UserPartner userPartnerOld = PartnerManager.getUserPartner(userId, partnerId);
                userPartnerOld.putBuildId(0);
                userPartnerOld.update();
                ProtoDataUtils.updatePBUserData(pbUserData, userPartnerOld);
            }
        }

        addValueEarn += userBuild.updatePartnerAdd(pbUserData, userInfo, userPower, partnerIdList.toString());
        userBuild.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userBuild);

        userPower.addBuildEarn(pbUserData, userInfo, addValueEarn);// // 增量更新城市收益

        int total = BuildManager.countPartnerNum(userId);// 统计所有商业建筑里派遣干员的总数量
        MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_106, total);// 更新主线任务,成就,日常任务的进度
        RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_106, total);

        return response;
    }

    // CMD_GAME_BUILD_COORD_UPDATE = 70708; // 翻转等修改坐标数据
    public static Object CMD_GAME_BUILD_COORD_UPDATE(RequestParam clientParam) throws Exception {
        CSGameBuildSavePlaceRequest request = CSGameBuildSavePlaceRequest.parseFrom(clientParam.getData());
        CSGameBuildSavePlaceResponse.Builder response = CSGameBuildSavePlaceResponse.newBuilder();
        long userId = clientParam.getUserId();

        PBUserCityCoord coord = request.getCoord();
        long key = BuildManager.takeCoord(coord.getX(), coord.getY(), coord.getZ());

        UserCityCoord userCityCoord = BuildManager.getUserCityCoord(userId, key);
        if (userCityCoord == null || userCityCoord.getItemId() == 0) {
            return ErrorWord.ENTITY_NOT_EXIST;// 这个坐标未摆放建筑
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        userCityCoord.putIsTurn(coord.getIsTurn());
        userCityCoord.putParam(coord.getParam());
        userCityCoord.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityCoord);

        return response;
    }

    // CMD_GAME_BUILD_CHANGE_NAME = 70709; // 城市改名
    public static Object CMD_GAME_BUILD_CHANGE_NAME(RequestParam clientParam) throws Exception {
        CSGameBuildChangeNameRequest request = CSGameBuildChangeNameRequest.parseFrom(clientParam.getData());
        CSGameBuildChangeNameResponse.Builder response = CSGameBuildChangeNameResponse.newBuilder();
        long userId = clientParam.getUserId();

        UserInfo userInfo = GameUser.getUserInfo(userId);
        String name = request.getName();
        ErrorWord errorWord = CommonUtils.checkString(name, AllParam.SYSTEM_NAME_WORDSNUM[0], AllParam.SYSTEM_NAME_WORDSNUM[1], false);// 最小2个字符,最大10个字符
        if (errorWord != ErrorWord.SUCCESS) {
            return errorWord;
        }

        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        if (userCityInfo.getCityName().equals(name)) {
            return ErrorWord.REPEATED_OPERATION;// 没有改变
        }

        int itemId = ItemId.CARD_CHANGE_NAME;// 优先使用改名卡
        long subNum = 1;// 改名卡扣一张
        long userItemNum = BagManager.getUserItemNum(userInfo, itemId);
        if (userItemNum < subNum) {
            itemId = ItemId.DIAMOND;// 无改名卡则用钻石
            subNum = AllParam.BUILD_CHANGE_NAME_DIAMOND_NUM;
        }
        userItemNum = BagManager.getUserItemNum(userInfo, itemId);// 判断钻石数量
        if (userItemNum < subNum) {
            return ErrorWord.ITEM_LACK;//
        }

        // 检测敏感字（先进行重名校验，在进行敏感词检测，防止重复刷文字校验api）
        String tempName = name;
        UserExtInfo userExtInfo = GameUser.getUserExtInfo(userId);
        try {
            name = SensitivewordEngine.replaceNameBySdk(name, userExtInfo.getPlatform());
        } catch (Exception e){
            return ErrorWord.BAD_WORD;
        }
        if (!tempName.equals(name)) {
            return ErrorWord.BAD_WORD;// 有敏感字
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        RewardManager.subReward(userInfo, itemId, subNum, pbUserData, LogType.BUILD_CHANGE_NAME);
        userCityInfo.putCityName(name);
        userCityInfo.update();
        GameUser.updateUserShow(userInfo, null);// 更新用户展示数据
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);

        return response;
    }

    // CMD_GAME_BUILD_GET_DAILY_DIAMOND = 70710; // 领取每日的钻石奖励
    public static Object CMD_GAME_BUILD_GET_DAILY_DIAMOND(RequestParam clientParam) throws Exception {
        CSGameBuildGetDailyDiamondRequest request = CSGameBuildGetDailyDiamondRequest.parseFrom(clientParam.getData());
        CSGameBuildGetDailyDiamondResponse.Builder response = CSGameBuildGetDailyDiamondResponse.newBuilder();
        long userId = clientParam.getUserId();

        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        if (TimeUtils.isToday(userCityInfo.getDailyDiamondTime())) {
            return ErrorWord.REPEATED_OPERATION;//  今天已经领取过了
        }
        UserBuild userBuild = BuildManager.getUserBuild(userId, BuildConstant.BUILD_ID_CITY_CENTER);//  市政中心
        UserExp userExp = GameDataManager.getUserExp(userBuild.getLevel());
        if (userExp == null || userExp.getDailyDiamond() == 0) {
            return ErrorWord.NOT_DATA;
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        RewardManager.addReward(userInfo, ItemId.DIAMOND, userExp.getDailyDiamond(), pbUserData, LogType.BUILD_DAILY_DIAMOND, userBuild.getLevel());
        userCityInfo.putDailyDiamondTime(TimeUtils.getCurTime());
        userCityInfo.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);

        return response;
    }

    // CMD_GAME_BUILD_BANK_GET_GOLD = 70711; // 点击金库领取金币
    public static Object CMD_GAME_BUILD_BANK_GET_GOLD(RequestParam clientParam) throws Exception {
        CSGameBuildBankGetGoldRequest request = CSGameBuildBankGetGoldRequest.parseFrom(clientParam.getData());
        CSGameBuildBankGetGoldResponse.Builder response = CSGameBuildBankGetGoldResponse.newBuilder();
        long userId = clientParam.getUserId();
        int num = request.getNum();
        if (num < 0 || num > 9999) {
            return ErrorWord.BAD_PARAM;
        }

        UserBuild userBuild = BuildManager.getUserBuild(userId, BuildConstant.BUILD_ID_BANK);//  金库
        if (userBuild == null || !userBuild.isPlace()) {
            return ErrorWord.WRONG_STATUS;// 未摆放金库
        }

        BuildBank buildBank = BuildManager.getBuildBank(userBuild.getLevel());
        if (buildBank == null) {
            return ErrorWord.NOT_DATA;
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        RewardManager.addReward(userInfo, ItemId.GOLD, buildBank.getRewardNum() * num, pbUserData, LogType.BUILD_BANK, buildBank.getRewardNum() + "_" + num);
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_11, num);// 更新主线任务,成就,日常任务的进度
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_101, num);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_11, num);
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_101, num);

        return response;
    }

    // CMD_GAME_BUILD_TILE_GET_REWARD = 70712; // 点击地图方块的奖励
    public static Object CMD_GAME_BUILD_TILE_GET_REWARD(RequestParam clientParam) throws Exception {
        CSGameBuildTileGetRewardRequest request = CSGameBuildTileGetRewardRequest.parseFrom(clientParam.getData());
        CSGameBuildTileGetRewardResponse.Builder response = CSGameBuildTileGetRewardResponse.newBuilder();
        long userId = clientParam.getUserId();

        int tileId = request.getTileId();
        int num = request.getNum();
        if (num < 0 || num > 999) {
            return ErrorWord.BAD_PARAM;
        }
        BuildTile buildTile = BuildManager.getBuildTile(tileId);
        if (buildTile == null) {
            return ErrorWord.NOT_DATA;// 不是金币废墟不能领取金币奖励
        }
        if (buildTile.getType() != BuildConstant.BUILD_TILE_TYPE_4 && buildTile.getType() != BuildConstant.BUILD_TILE_TYPE_9) {
            return ErrorWord.WRONG_STATUS;// 不是金币废墟
        }
        int maxNum = buildTile.getValue1();// 当type=4时表示 废墟可以点击的最大次数
        if (num == 0) {
            num = 1;
        } else if (num > maxNum) {
            num = maxNum;// 最少1次，不能超过上限
        }


        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserBuildTile userBuildTile = BuildManager.getUserBuildTile(userId, tileId);
        boolean isInit = false;
        if (userBuildTile == null)  {
            userBuildTile = new UserBuildTile(userId, tileId, num);
            userBuildTile.doCreate();
            isInit = true;
        } else {
            if (userBuildTile.getNum() >= maxNum) {
                return ErrorWord.ALREADY_MAX;// 次数达到上限
            }
            if (userBuildTile.getNum() + num > maxNum) {
                num = maxNum - userBuildTile.getNum();// 不能超过上限
            }
            userBuildTile.addNum(num);// 更新次数
            userBuildTile.update();
        }
        UserInfo userInfo = GameUser.getUserInfo(userId);
        RewardManager.addReward(userInfo, ItemId.GOLD, buildTile.getValue2() * num, pbUserData, LogType.BUILD_TILE_REWARD, buildTile.getValue2() + "_" + num);
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_241, num);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_241, num);

        ProtoDataUtils.updatePBUserData(pbUserData, userBuildTile, isInit);

        return response;
    }

    // CMD_GAME_BUILD_TILE_REBUILD = 70713; // 地图方块的可修复废墟重建
    public static Object CMD_GAME_BUILD_TILE_REBUILD(RequestParam clientParam) throws Exception {
        CSGameBuildTileRebuildRequest request = CSGameBuildTileRebuildRequest.parseFrom(clientParam.getData());
        CSGameBuildTileRebuildResponse.Builder response = CSGameBuildTileRebuildResponse.newBuilder();
        long userId = clientParam.getUserId();

        int tileId = request.getTileId();
        int isTurn = request.getIsTurn();// 是否翻转

        BuildTile buildTile = BuildManager.getBuildTile(tileId);
        if (buildTile == null) {
            return ErrorWord.NOT_DATA;// 不是可修复的废墟不能重建
        }
        if (!buildTile.isUnlockAndPlace() && !buildTile.isOnlyPlace()) {
            return ErrorWord.NOT_DATA;// 只有这两种类型的废墟可以修复 不是可修复的废墟不能重建
        }

        UserBuildTile userBuildTile = BuildManager.getUserBuildTile(userId, tileId);
        if (userBuildTile != null) {
            return ErrorWord.REPEATED_OPERATION;// 已经重建过了
        }

        int buildId = buildTile.getValue1();// 当type=7时表示 修复建筑后放置的建筑ID
        BuildMain buildMain = BuildManager.getBuildMain(buildId);

        UserInfo userInfo = GameUser.getUserInfo(userId);// 从废墟修复的建筑，要解锁也必须符合解锁条件
        if (buildTile.isUnlockAndPlace() && !BuildManager.isCanUnlock(buildMain, userInfo)) {
            return ErrorWord.WRONG_STATUS;//未达到解锁条件
        }

        int itemId = ItemId.GOLD;//
        int subNum = buildTile.getValue2();// 重建需要消耗的金币数量
        long userItemNum = BagManager.getUserItemNum(userInfo, itemId);
        if (userItemNum < subNum) {
            return ErrorWord.ITEM_LACK;//  金币不足
        }

        long coord = BuildManager.takeCoord(request.getX(), request.getY(), request.getZ());
        UserCityCoord userCityCoord = BuildManager.getUserCityCoord(userId, coord);
        if (userCityCoord != null) {
            return ErrorWord.REPEATED_OPERATION;// 该坐标已经有建筑
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        RewardManager.subReward(userInfo, itemId, subNum, pbUserData, LogType.BUILD_TILE_REBUILD);

        if (buildTile.isUnlockAndPlace()) {// 需要解锁
            UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
            if (userBuild == null) {
                UserPower userPower = GameUser.getUserPower(userId);
                userBuild = new UserBuild(userId, buildId, 1, 1);// 创建用户数据
                userBuild.putIsPlace(pbUserData, userInfo, userPower);
                userBuild.doCreate();
                ProtoDataUtils.updatePBUserData(pbUserData, userBuild, true);

                if (buildMain.isCityCenter()) {
                    MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_113, userBuild.getLevel());// 更新主线任务,成就,日常任务的进度
                    RankActManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_113, userBuild.getLevel());
                } else if (buildMain.isBuildRadar()) {// 雷达
                    MainTaskManager.updateTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_255, userBuild.getLevel());// 雷达等级提升至{0}级
                }
            }
        }

        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_243, 1, buildId);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_243, 1, buildId);
        userCityCoord = new UserCityCoord(userId, coord, buildId, isTurn, "", TimeUtils.getCurTime());
        userCityCoord.doCreate();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityCoord, true);

        userBuildTile = new UserBuildTile(userId, tileId, true);
        userBuildTile.doCreate();
        ProtoDataUtils.updatePBUserData(pbUserData, userBuildTile, true);

        if (buildMain.getPeasonLimit() > 0) {// 摆放民房会增加居民楼的数量
            UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
            userCityInfo.addPeasonMax(pbUserData, userInfo, buildMain.getPeasonLimit());
            userCityInfo.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);
        }

        return response;
    }

    // CMD_GAME_BUILD_SYNC_CITY_EARN = 70714; // 客户端同步城市收益,1分钟请求一次
    public static Object CMD_GAME_BUILD_SYNC_CITY_EARN(RequestParam clientParam) throws Exception {
        CSGameBuildSyncCityEarnRequest request = CSGameBuildSyncCityEarnRequest.parseFrom(clientParam.getData());
        CSGameBuildSyncCityEarnResponse.Builder response = CSGameBuildSyncCityEarnResponse.newBuilder();
        long userId = clientParam.getUserId();

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        UserAffair userAffair = GameUser.getUserAffair(userId);
        UserPower userPower = GameUser.getUserPower(userId);

        GameUser.handleSyncData(pbUserData, userInfo, userPower, userAffair);// 同步各种有时效的加成效果，称号，兽潮，地下洞窟被打,联盟建筑加成，

        BuildManager.countTotalEarnNow(pbUserData, userInfo, userPower, userAffair, false);// 按当前时间的临时收益结算到当前时间的城市收益有多少

        // 金库自动点击的奖励
        UserBuild userBuild = BuildManager.getUserBuild(userId, BuildConstant.BUILD_ID_BANK);
        if (userBuild != null && userBuild.isPlace()) {
            BuildBank buildBank = BuildManager.getBuildBank(userBuild.getLevel());
            if (buildBank != null && buildBank.getSecondNum() > 0 && buildBank.getRewardNum() > 0) {
                UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
                long diffTime = TimeUtils.getTimeDiff(userCityInfo.getBankRewardTime());
                diffTime = Math.min(diffTime, TimeUtils.MINUTE);// 上限不能超过1分钟
                long itemNum = buildBank.getRewardNum() * buildBank.getSecondNum() * diffTime;
                RewardManager.addReward(userInfo, ItemId.GOLD, itemNum, pbUserData, LogType.BUILD_BANK_AUOT);
                userCityInfo.putBankRewardTime(TimeUtils.getCurTime());
                userCityInfo.update();
            }
        }

        return response;
    }


    // CMD_GAME_BUILD_SAVE_PLACE_BATCH = 70715; // 批量摆放简单的建筑，不设置城市收益，人口等数据
    public static Object CMD_GAME_BUILD_SAVE_PLACE_BATCH(RequestParam clientParam) throws Exception {
        CSGameBuildSavePlaceBatchRequest request = CSGameBuildSavePlaceBatchRequest.parseFrom(clientParam.getData());
        CSGameBuildSavePlaceBatchResponse.Builder response = CSGameBuildSavePlaceBatchResponse.newBuilder();
        long userId = clientParam.getUserId();

        List<PBUserCityCoord> coords = request.getCoordsList();

        List<RewardItem> needItem = new ArrayList<>();
        for (PBUserCityCoord coord : coords) {
            long key = BuildManager.takeCoord(coord.getX(), coord.getY(), coord.getZ());
            int buildId = coord.getItemId();
            BuildMain buildMain = BuildManager.getBuildMain(buildId);
            if (buildMain == null) {
                return ErrorWord.BAD_PARAM;
            }
            UserBuild userBuild = BuildManager.getUserBuild(userId, buildId);
            if (!BuildManager.checkBuildCanPlace(buildMain, userBuild)) {
                return ErrorWord.WRONG_STATUS;// 建筑未解锁
            }
            CommonUtils.mergeItemList(needItem, CommonUtils.takeReawrdItemFromStr(buildMain.getPlaceItem()));// 需要消耗的道具
        }

        UserInfo userInfo = GameUser.getUserInfo(userId);
        if (needItem.size() > 0 && !BagManager.checkNeedItemNum(userInfo, needItem)) {
            return ErrorWord.ITEM_LACK;
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        if (needItem.size() > 0) {
            RewardManager.subReward(userInfo, needItem, pbUserData, LogType.BUILD_PLACE);
        }

        // 生成新的坐标信息并下发客户端
        for (PBUserCityCoord coord : coords) {
            long key = BuildManager.takeCoord(coord.getX(), coord.getY(), coord.getZ());
            UserCityCoord userCityCoord = BuildManager.getUserCityCoord(userId, key);
            int buildId = coord.getItemId();
            BuildManager.creatUserCityCoord(pbUserData, userCityCoord, userId, key, buildId, coord.getIsTurn(), coord.getParam(), TimeUtils.getCurTime());
        }

        return response;
    }

    // CMD_GAME_BUILD_HOSPITAL_MAIN_INFO = 70716; // 进入医院页面，下发最新兵力，和伤员的恢复信息[2]每次打开请求
    public static Object CMD_GAME_BUILD_HOSPITAL_MAIN_INFO(RequestParam clientParam) throws Exception {
        CSGameBuildHospitalMainInfoRequest request = CSGameBuildHospitalMainInfoRequest.parseFrom(clientParam.getData());
        CSGameBuildHospitalMainInfoResponse.Builder response = CSGameBuildHospitalMainInfoResponse.newBuilder();

        long userId = clientParam.getUserId();

        UserSoldierRecover userSoldierRecover = BuildManager.getUserSoldierRecover(userId);
        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        PBUserData.Builder pbUserData = response.getUserBuilder();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo, true);
        ProtoDataUtils.updatePBUserData(pbUserData, userSoldierRecover, true);

        return response;
    }

    // CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER = 70717; // 伤员进行治疗恢复兵力
    public static Object CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER(RequestParam clientParam) throws Exception {
        CSGameBuildHospitalRecoverSoldierRequest request = CSGameBuildHospitalRecoverSoldierRequest.parseFrom(clientParam.getData());
        CSGameBuildHospitalRecoverSoldierResponse.Builder response = CSGameBuildHospitalRecoverSoldierResponse.newBuilder();

        long userId = clientParam.getUserId();
        int type = request.getType();// 类型
        int num = request.getNum();// 伤兵数量
        boolean isQuick = request.getIsQuick();// 是否直接消耗钻石，直接治疗完成


        BuildHospital buildHospital = BuildManager.getBuildHospital(type);
        if (buildHospital == null) {
            return ErrorWord.NOT_DATA;
        }

        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        if (!buildHospital.isUnlock(userCityInfo)) {
            return ErrorWord.WRONG_STATUS;// 快速治疗未解锁
        }

        if (userCityInfo.getSoldierWound() < num) {
            return ErrorWord.ALREADY_MAX;//治疗数量超过当前的伤兵数量
        }

        UserSoldierRecover userSoldierRecover = BuildManager.getUserSoldierRecover(userId);
        if (userSoldierRecover.isRecovering()) {
            return ErrorWord.REPEATED_OPERATION;// 当前正在治疗中
        }

        List<RewardItem> costReward = BuildManager.countSoldierRecoverItem(type, num);// 恢复伤员需要消耗的道具
        int skillValue = SkillManager.getSkillMoudleAdd(userId, SkillConstant.EFFECT_TYPE_106, 0);// 技能减少的百分比
        CommonUtils.modifyRewardItem(costReward, -skillValue);

        long curTime = TimeUtils.getCurTime();
        int recoverValue = BuildManager.getRecoverValue(userId, buildHospital);// 实际的恢复速度
        long costTime = BuildManager.countRecoverSoldierTime(recoverValue, num);// 总的需要时间
        if (isQuick) {//  快速消耗的钻石不在技能减少
            int itemId = ItemId.DIAMOND;// 快速治疗需要额外消耗钻石
            long itemNum = BuildManager.getRecoverQuickItemNum(costTime);// // 快速治疗需要消耗的钻石数量
            costReward.add(new RewardItem(itemId, itemNum));
        }

        UserInfo userInfo = GameUser.getUserInfo(userId);
        if (!BagManager.checkNeedItemNum(userInfo, costReward)) {
            return ErrorWord.ITEM_LACK;// 道具不足
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        RewardManager.subReward(userInfo, costReward, pbUserData, LogType.BUILD_HOSPITAL_RECOVER_SOLDIER);
        if (!isQuick) {// 非快速治疗，需要生成治疗数据
            userSoldierRecover.putSoldierTotal(num);
            userSoldierRecover.putType(type);
            userSoldierRecover.putStartTime(curTime);
            userSoldierRecover.putEndTime(curTime + costTime);
            userSoldierRecover.putRecoverValue(recoverValue);
            userSoldierRecover.putUniqeId(Tool.getUUID());
            userSoldierRecover.putReduceTime(0);
            userSoldierRecover.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userSoldierRecover, true);
        }

        userCityInfo.addSoldierWound(-num);// 扣除未恢复的伤兵数量
        userCityInfo.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);

        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_72, 1);// 在医院进行{0}次伤员治疗

        return response;
    }

    // CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER_QUICK = 70718; // 伤员进行治疗恢复兵力 消耗钻石提早结束
    public static Object CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER_QUICK(RequestParam clientParam) throws Exception {
        CSGameBuildHospitalRecoverSoldierQuickRequest request = CSGameBuildHospitalRecoverSoldierQuickRequest.parseFrom(clientParam.getData());
        CSGameBuildHospitalRecoverSoldierQuickResponse.Builder response = CSGameBuildHospitalRecoverSoldierQuickResponse.newBuilder();

        long userId = clientParam.getUserId();
        UserSoldierRecover userSoldierRecover = BuildManager.getUserSoldierRecover(userId);
        if (!userSoldierRecover.isRecovering()) {
            return ErrorWord.WRONG_STATUS;// 当前不是治疗中
        }

        UserInfo userInfo = GameUser.getUserInfo(userId);
        long costTime = userSoldierRecover.getEndTime() - TimeUtils.getCurTime();
        long subNum = BuildManager.getRecoverQuickItemNum(costTime);// 快速治疗需要消耗的钻石数量
        int itemId = ItemId.DIAMOND;
        long userItemNum = BagManager.getUserItemNum(userInfo, itemId);
        if (userItemNum < subNum) {
            return ErrorWord.ITEM_LACK;// 钻石不足
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        RewardManager.subReward(userInfo, itemId, subNum, pbUserData, LogType.BUILD_HOSPITAL_RECOVER_SOLDIER);
        userSoldierRecover.cleanData();
        userSoldierRecover.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userSoldierRecover);

        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo, true);

        return response;
    }

    // CMD_GAME_BUILD_RADAR_GET_LEVEL_REWARD = 70719; // 领取雷达的升级奖励
    public static Object CMD_GAME_BUILD_RADAR_GET_LEVEL_REWARD(RequestParam clientParam) throws Exception {
        CSGameBuildRadarGetLevelRewardRequest request = CSGameBuildRadarGetLevelRewardRequest.parseFrom(clientParam.getData());
        CSGameBuildRadarGetLevelRewardResponse.Builder response = CSGameBuildRadarGetLevelRewardResponse.newBuilder();

        long userId = clientParam.getUserId();
        UserBuild userBuild = BuildManager.getUserBuild(userId, BuildConstant.BUILD_ID_RADAR);
        if (userBuild == null) {
            return ErrorWord.WRONG_STATUS;
        }

        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        if (userCityInfo.getRadarLevelReward() >= userBuild.getLevel()) {
            return ErrorWord.REPEATED_OPERATION;// 已经领取过了
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        for (int i=userCityInfo.getRadarLevelReward() + 1; i<=userBuild.getLevel(); i++) {
            WorldRadar worldRadar = WorldManager.getWorldRadar(i);
            if (worldRadar != null && !Tool.isEmpty(worldRadar.getReward())) {
                RewardManager.addReward(userInfo, CommonUtils.takeReawrdItemFromStr(worldRadar.getReward()), pbUserData, LogType.BUILD_RADAR_LEVEL_REWARD, i);
            }
        }
        userCityInfo.putRadarLevelReward(userBuild.getLevel());
        userCityInfo.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);

        return response;
    }


    // CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER_CANCEL = 70720; // 伤员进行治疗恢复兵力，取消治疗
    public static Object CMD_GAME_BUILD_HOSPITAL_RECOVER_SOLDIER_CANCEL(RequestParam clientParam) throws Exception {
        CSGameBuildHospitalRecoverSoldierCancelRequest request = CSGameBuildHospitalRecoverSoldierCancelRequest.parseFrom(clientParam.getData());
        CSGameBuildHospitalRecoverSoldierCancelResponse.Builder response = CSGameBuildHospitalRecoverSoldierCancelResponse.newBuilder();

        long userId = clientParam.getUserId();

        UserSoldierRecover userSoldierRecover = BuildManager.getUserSoldierRecover(userId);
        if (!userSoldierRecover.isRecovering()) {
            return ErrorWord.WRONG_STATUS;// 当前不是在治疗中
        }

        // 执行逻辑
        PBUserData.Builder pbUserData = response.getUserBuilder();
        UserInfo userInfo = GameUser.getUserInfo(userId);
        UserCityInfo userCityInfo = BuildManager.getUserCityInfo(userId);
        int type = userSoldierRecover.getType();// 治疗类型
        int num = userSoldierRecover.getSoldierTotal();// 治疗数量
        List<RewardItem> costReward = BuildManager.countSoldierRecoverItem(type, num);// 恢复伤员需要消耗的道具
        int skillValue = SkillManager.getSkillMoudleAdd(userId, SkillConstant.EFFECT_TYPE_106, 0);// 技能减少的百分比
        CommonUtils.modifyRewardItem(costReward, -skillValue);//  会有误差忽略不计
        RewardManager.addReward(userInfo, costReward, pbUserData, LogType.BUILD_HOSPITAL_RECOVER_SOLDIER_CANCEL, type + "_" + num);

        userCityInfo.addSoldierWound(num);// 把治疗的伤兵数量加回去
        userCityInfo.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userCityInfo);

        userSoldierRecover.cleanData();
        userSoldierRecover.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userSoldierRecover);

        return response;
    }
}
